package com.cn.auth.config.custom.sms;

import com.alibaba.fastjson.JSON;
import com.cn.auth.redis.RedisConstant;
import com.cn.auth.service.UserDetailService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.token.AbstractTokenGranter;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author: zhoujunming
 * @Description: 短信验证码Token key的生成规则
 * @date: 2024/1/5 13:20
 * @email: zhoujunming@bluemoon.com.cn
 */
public class SmsCodeTokenGranter extends AbstractTokenGranter {

    private static final String SMS_GRANT_TYPE = "sms_code";

    private UserDetailService userDetailsService;

    private RedisTemplate redisTemplate;

    public SmsCodeTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory,UserDetailService userDetailsService,RedisTemplate redisTemplate) {
        super(tokenServices, clientDetailsService, requestFactory, SMS_GRANT_TYPE);
        this.userDetailsService = userDetailsService;
        this.redisTemplate = redisTemplate;
    }

    @Override
    protected OAuth2Authentication getOAuth2Authentication(ClientDetails client,
                                                           TokenRequest tokenRequest) {

        Map<String, String> parameters = new LinkedHashMap<>(tokenRequest.getRequestParameters());
        logger.info(JSON.toJSONString(parameters));
        //客户端提交的手机号码
        String phoneNumber = parameters.get("phone");
        //客户端输入的用户(多种业务场景，有的不需要传用户)
        String userName = parameters.get("userName");
        //客户端id
        String clientId = parameters.get("clientId");
        // 客户端提交的验证码
        String smsCode = parameters.get("code");
        if (StringUtils.isBlank(smsCode)){
            throw new AccessDeniedException("验证码不能为空");
        }
        if (StringUtils.isBlank(clientId)){
            throw new AccessDeniedException("客户端id不能为空");
        }
        if (StringUtils.isBlank(phoneNumber)) {
            throw new AccessDeniedException("手机号码不能为空");
        }
        String userId = StringUtils.isBlank(userName)?phoneNumber:userName;

        UserDetails user = userDetailsService.loadUserByUsername(userId);
        if (StringUtils.isNotBlank(userName)){
            //业务逻辑-校验用户数据库的手机号和输入手机号是否一致
        }

        //从redis获取短信验证码
        Object redisSmsCode = redisTemplate.opsForValue().get(RedisConstant.SMS_CODE +"_"+ phoneNumber +"_"+ clientId +"_"+ smsCode);

        if (!smsCode.equals(String.valueOf(redisSmsCode))) {
            throw new AccessDeniedException("验证码输入不正确!");
        }

        AbstractAuthenticationToken userAuth = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());

        userAuth.setDetails(parameters);
        OAuth2Request oAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest);
        return new OAuth2Authentication(oAuth2Request, userAuth);
    }
}
